import { createAction, createReducer, ActionType, createAsyncAction } from 'typesafe-actions';
import { Dispatch } from 'redux';
import Axios from 'axios';
import _ from 'lodash';

export interface WordTagSelectIndexDto {
    wordTagValue: string;
}

export interface WordTagSelectDto {
    dtos: WordTagSelectIndexDto[]
}
export interface WordTagSelectState {
    dto: WordTagSelectDto
    currentTagValue: string
    currentTagValueInner: string | null
}

const setState = createAction('WORD_TAG_SELECT/SET_STATE')<WordTagSelectState>();
export const setCurrentTagValue = createAction('WORD_TAG_SELECT/SET_CURRENT_TAG_VALUE')<string>();
export const setCurrentTagValueInner = createAction('WORD_TAG_SELECT/SET_CURRENT_TAG_VALUE_INNER')<string>();

const fetchActions = createAsyncAction(
    'WORD_TAG_SELECT/FETCH/REQUEST',
    ['WORD_TAG_SELECT/FETCH/SUCCESS', (res: WordTagSelectDto) => res],
    ['WORD_TAG_SELECT/FETCH/FAILURE', (err: Error) => err],
    'WORD_TAG_SELECT/FETCH/CANCEL',
)();

const addActions = createAsyncAction(
    'WORD_TAG_SELECT/ADD/REQUEST',
    ['WORD_TAG_SELECT/ADD/SUCCESS', (res: string) => res],
    ['WORD_TAG_SELECT/ADD/FAILURE', (err: Error) => err],
    'WORD_TAG_SELECT/ADD/CANCEL',
)();

const editActions = createAsyncAction(
    'WORD_TAG_SELECT/EDIT/REQUEST',
    ['WORD_TAG_SELECT/EDIT/SUCCESS', (res: { newValue: string, oldValue: string }) => res],
    ['WORD_TAG_SELECT/EDIT/FAILURE', (err: Error) => err],
    'WORD_TAG_SELECT/EDIT/CANCEL',
)();

const removeActions = createAsyncAction(
    'WORD_TAG_SELECT/REMOVE/REQUEST',
    ['WORD_TAG_SELECT/REMOVE/SUCCESS', (res: string) => res],
    ['WORD_TAG_SELECT/REMOVE/FAILURE', (err: Error) => err],
    'WORD_TAG_SELECT/REMOVE/CANCEL',
)();

export type Actions = ActionType<typeof setState>
    | ActionType<typeof fetchActions>
    | ActionType<typeof addActions>
    | ActionType<typeof editActions>
    | ActionType<typeof removeActions>
    | ActionType<typeof setCurrentTagValue>
    | ActionType<typeof setCurrentTagValueInner>
    ;

export const fetch = () =>
    async (dispatch: Dispatch) =>
        Axios.get<WordTagSelectDto>(`wordTag`)
            .then(res => dispatch(fetchActions.success(res.data)))
            .catch(error => dispatch(fetchActions.failure(error)))

export const add = (wordTagValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.post(`wordTag/${wordTagValue}`)
            .then(_ => dispatch(addActions.success(wordTagValue)))
            .catch(err => dispatch(addActions.failure(err)))

export const edit = (oldValue: string, newValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.put(`wordTag/${oldValue}/${newValue}`)
            .then(_ => dispatch(editActions.success({ newValue, oldValue })))
            .catch(err => dispatch(editActions.failure(err)))

export const remove = (wordTagValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.delete(`wordTag/${wordTagValue}`)
            .then(_ => dispatch(removeActions.success(wordTagValue)))
            .catch(err => dispatch(removeActions.failure(err)))

const initialState: WordTagSelectState = {
    dto: { dtos: [] },
    currentTagValue: '默认',
    currentTagValueInner: null,
};

export const Reducer = createReducer<WordTagSelectState, Actions>(initialState)
    .handleAction(setState, (_, action) => action.payload)
    .handleAction(setCurrentTagValue, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.currentTagValue = action.payload
        return newState
    })
    .handleAction(setCurrentTagValueInner, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.currentTagValueInner = action.payload
        return newState
    })
    .handleAction(fetchActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.dto = action.payload
        // newState.dto.dtos.unshift({ wordTagValue: "无" })
        return newState
    })
    .handleAction(addActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.dto.dtos.push({ wordTagValue: action.payload });
        return newState
    })
    .handleAction(editActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        const i = newState.dto.dtos.findIndex(e => e.wordTagValue === action.payload.oldValue);
        newState.dto.dtos[i].wordTagValue = action.payload.newValue
        return newState
    })
    .handleAction(removeActions.success, (state, action) => {
        const newState = _.cloneDeep(state)
        const arr = newState.dto.dtos.filter(e => e.wordTagValue !== action.payload)
        newState.dto.dtos = arr
        return newState
    })